/* vim:ft=objc:
 * $Id: Keychain.m 114 2005-05-12 05:15:40Z bmoore $
 *
 * Copyright (c) 2004, 2005  Branden J. Moore.
 *
 * This file is part of MacBiff, and is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * MacBiff is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MacBiff; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307 USA.
 *
 */

#import "Keychain.h"

#if 1
#  define EBUG 1
#endif
#include "debug.h"
#include "xmalloc.h"

Keychain *keychain = Nil;

@implementation Keychain

- (id) init
{
	if ( (self = [super init]) != Nil ) {
		lock1 = [[NSLock alloc] init];
		lock2 = [[NSLock alloc] init];
		[lock2 lock];
	}
	keychain = self;
	return self;
}


- (void) dealloc
{
	if ( lock1 ) {
		[lock1 unlock];
		[lock1 release];
	}
	if ( lock2 ) {
		[lock2 unlock];
		[lock2 release];
	}
	[super dealloc];
}


- (IBAction) passwordFromUser: (id) sender
{
	fetchedpw = [[NSString alloc] initWithString:
		[passwordTextField stringValue]];
	[passwordWin close];
	[lock2 unlock]; /* Signify that we've got the password */
}


- (NSString*) getKeyChain: (SecKeychainItemRef*) ref
		andStatus: (OSStatus*) status
	  PasswordForUser: (NSString*) u
		   onHost: (NSString*) h
		   atPort: (UInt16) pt
		withProto: (SecProtocolType) proto
{
	void *tpw = NULL;
	NSString *pw = Nil;
	UInt32 len;

	*status = SecKeychainFindInternetPassword(
			NULL,
			[h length],
			[h cString],
			0, NULL,
			[u length],
			[u cString],
			0, NULL,
			pt, proto,
			kSecAuthenticationTypeDefault,
			&len, (void**)&tpw,
			ref);

	if ( tpw && *status == noErr ) {
		pw = [[NSString alloc] initWithCString: tpw length: len];
		SecKeychainItemFreeContent(NULL, tpw);
	}
	return [pw autorelease];
}


- (void) savePassword: (NSString*) pw
	      forUser: (NSString*) u
	       onHost: (NSString*) h
	       atPort: (UInt16) pt
	    withProto: (SecProtocolType) proto
{
	OSStatus status;
	SecKeychainItemRef ref;
	[self getKeyChain: &ref andStatus: &status PasswordForUser: u
			onHost: h atPort: pt withProto: proto];

	if ( status == errSecItemNotFound ) {
		SecKeychainAddInternetPassword(
				NULL,
				[h length],
				[h cString],
				0, NULL,
				[u length],
				[u cString],
				0, NULL,
				pt, proto,
				kSecAuthenticationTypeDefault,
				[pw length],
				[pw cString],
				NULL);
	} else {
		SecKeychainItemModifyAttributesAndData( ref, NULL,
				[pw length], [pw cString]);
	}
}


- (NSString*) getPasswordForUser: (NSString*) u
			  onHost: (NSString*) h
			  atPort: (UInt16) pt
		       withProto: (SecProtocolType) proto
			byAsking: (BOOL) ask;
{
	OSStatus status;
	NSString *pw = Nil;
	pw = [self getKeyChain: NULL andStatus: &status PasswordForUser: u
			onHost: h atPort: pt withProto: proto];

	/* If we got the password, or are not to ask, just return */
	if ( pw || !ask ) {
		return pw;
	}

	/* Somehow, ask for the password from the user */
	[lock1 lock]; /* Lock the window */
	[usernameTextField setStringValue: u];
	[hostnameTextField setStringValue: h];
	[passwordWin makeKeyAndOrderFront: self];
	[NSApp activateIgnoringOtherApps: YES];
	/* Wait for fetchedpw to be set */
	[lock2 lock];
	pw = [fetchedpw autorelease];
	[lock1 release];
	[self savePassword: pw forUser: u onHost: h atPort: pt withProto: proto];
	return pw;

}


@end
